package com.cskaoyan.wordmemorize.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cskaoyan.wordmemorize.common.annotation.OperateLog;
import com.cskaoyan.wordmemorize.common.constant.ResultCodeEnum;
import com.cskaoyan.wordmemorize.common.exception.BusinessException;
import com.cskaoyan.wordmemorize.converter.RolePermissionConverter;
import com.cskaoyan.wordmemorize.dao.entity.PermissionDO;
import com.cskaoyan.wordmemorize.dao.entity.RoleDO;
import com.cskaoyan.wordmemorize.dao.entity.RolePermissionDO;
import com.cskaoyan.wordmemorize.dao.mapper.PermissionMapper;
import com.cskaoyan.wordmemorize.dao.mapper.RoleMapper;
import com.cskaoyan.wordmemorize.dao.mapper.RolePermissionMapper;
import com.cskaoyan.wordmemorize.dto.admin.*;
import com.cskaoyan.wordmemorize.request.PageRequest;
import com.cskaoyan.wordmemorize.request.PermissionCommand;
import com.cskaoyan.wordmemorize.request.RoleCommand;
import com.cskaoyan.wordmemorize.request.RolePermissionCommand;
import com.cskaoyan.wordmemorize.service.RolePermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;


import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色权限关系服务实现类
 */
@Service
public class RolePermissionServiceImpl extends ServiceImpl<RolePermissionMapper, RolePermissionDO> implements RolePermissionService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private RolePermissionConverter rolePermissionConverter;


    /**
     * 保存权限树(后台账号权限管理-权限管理)
     *
     * @param command 权限对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @OperateLog(dateType = "权限", operateType = 1)
    public void savePermissions(PermissionCommand command) {
        // 检查权限码是否已存在
        LambdaQueryWrapper<PermissionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PermissionDO::getPermissionCode, command.getPermissionCode());
        if (permissionMapper.selectCount(queryWrapper) > 0) {
            throw new BusinessException("权限码已存在", ResultCodeEnum.FAIL.getCode());
        }

        // 转换为DO并保存
        PermissionDO permissionDO = rolePermissionConverter.command2PermissionDO(command);

        // 如果有父权限，设置父权限ID
        if (StringUtils.hasLength(command.getParentPermission()) && !"-1".equals(command.getParentPermission())) {
            permissionDO.setParentPermission(Long.valueOf(command.getParentPermission()));
        } else {
            permissionDO.setParentPermission(null); // 没有父权限
        }

        permissionMapper.insert(permissionDO);

        // 如果有子权限，递归保存
        if (!CollectionUtils.isEmpty(command.getChildren())) {
            for (PermissionCommand child : command.getChildren()) {
                // 设置父权限ID
                child.setParentPermission(String.valueOf(permissionDO.getId()));
                savePermissions(child);
            }
        }
    }

    /**
     * 获取权限树(后台账号权限管理-权限管理)
     *
     * @return 返回权限树
     */
    @Override
    public List<PermissionDTO> getPermissions() {
        // 获取所有权限
        List<PermissionDO> permissionDOList = permissionMapper.selectList(null);

        // 转换为DTO
        List<PermissionDTO> permissionDTOList = rolePermissionConverter.employeePermissionDO2DTO(permissionDOList);

        // 构建权限树
        return buildPermissionTree(permissionDTOList);
    }

    /**
     * 删除指定权限(后台账号权限管理-权限管理)
     *
     * @param permissionId 权限ID
     * @return 返回删除操作日志结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @OperateLog(dateType = "权限", operateType = 3)
    public DeletePermissionOperateDTO deletePermission(Long permissionId) {
        // 检查权限是否存在
        PermissionDO permissionDO = permissionMapper.selectById(permissionId);
        if (permissionDO == null) {
            throw new BusinessException("权限不存在", ResultCodeEnum.FAIL.getCode());
        }

        // 检查是否有子权限
        LambdaQueryWrapper<PermissionDO> childQueryWrapper = new LambdaQueryWrapper<>();
        childQueryWrapper.eq(PermissionDO::getParentPermission, permissionId);
        if (permissionMapper.selectCount(childQueryWrapper) > 0) {
            throw new BusinessException("该权限存在子权限，无法删除", ResultCodeEnum.PERMISSION_CAN_NOT_DELETE.getCode());
        }

        // 删除角色权限关系
        LambdaQueryWrapper<RolePermissionDO> rolePermQueryWrapper = new LambdaQueryWrapper<>();
        rolePermQueryWrapper.eq(RolePermissionDO::getPermissionId, permissionId);
        remove(rolePermQueryWrapper);

        // 删除权限
        permissionMapper.deleteById(permissionId);

        // 构建操作日志
        return rolePermissionConverter.toDeletePermissionOperateDTO(permissionDO);
    }

    /**
     * 更新权限树(后台账号权限管理-权限管理)
     *
     * @param command 权限对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @OperateLog(dateType = "权限", operateType = 2)
    public void updatePermission(PermissionCommand command) {
        // 检查权限是否存在
        PermissionDO existPermission = permissionMapper.selectById(command.getId());
        if (existPermission == null) {
            throw new BusinessException("权限不存在", ResultCodeEnum.FAIL.getCode());
        }

        // 检查权限码是否重复
        if (!existPermission.getPermissionCode().equals(command.getPermissionCode())) {
            LambdaQueryWrapper<PermissionDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(PermissionDO::getPermissionCode, command.getPermissionCode());
            if (permissionMapper.selectCount(queryWrapper) > 0) {
                throw new BusinessException("权限码已存在", ResultCodeEnum.FAIL.getCode());
            }
        }

        // 转换为DO并更新
        PermissionDO permissionDO = rolePermissionConverter.command2PermissionDO(command);

        // 如果有父权限，设置父权限ID
        if (StringUtils.hasLength(command.getParentPermission()) && !"-1".equals(command.getParentPermission())) {
            permissionDO.setParentPermission(Long.valueOf(command.getParentPermission()));
        } else {
            permissionDO.setParentPermission(null); // 没有父权限
        }

        permissionMapper.updateById(permissionDO);
    }

    /**
     * 分页获取角色列表(后台账号权限管理-角色管理)
     *
     * @param pageRequest 分页请求对象
     * @return 返回角色列表
     */
    @Override
    public PageDTO<RoleDTO> getRoleList(PageRequest pageRequest) {
        // 构建分页对象的默认参数，默认从第一页开始，每页显示10条记录
        int pageNum = pageRequest.getPageNum() != null ? pageRequest.getPageNum() : 1;
        int count = pageRequest.getCount() != null ? pageRequest.getCount() : 10;
        // 构建分页对象
        Page<RoleDO> page = new Page<>(pageNum, count);

        // 构建查询条件
        LambdaQueryWrapper<RoleDO> queryWrapper = new LambdaQueryWrapper<>();

        // 如果有关键词，则添加模糊查询条件——员工姓名
        if (org.apache.commons.lang3.StringUtils.isNotBlank(pageRequest.getKeyword())) {
            queryWrapper.like(RoleDO::getName, pageRequest.getKeyword());
        }
        // 因为IService使用的是RolePermissionDO，所以这里没办法用RolePermissionMapper的分页查询去查询RoleDO
        // 所以这里要使用注入的RoleMapper的selectPage方法查询数据库
        Page<RoleDO> resultPage = roleMapper.selectPage(page, queryWrapper);

        // 转换为DTO并返回
        return rolePermissionConverter.roleList2Page(resultPage.getRecords(), resultPage.getTotal());
    }

    /**
     * 添加角色(后台账号权限管理-角色管理)
     *
     * @param command 角色对象
     * @return 新创建角色的ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @OperateLog(dateType = "角色", operateType = 1)
    public Long addRole(RoleCommand command) {
        // 检查角色名称是否已存在
        LambdaQueryWrapper<RoleDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RoleDO::getName, command.getName());
        if (roleMapper.selectCount(queryWrapper) > 0) {
            throw new BusinessException("角色名称已存在", ResultCodeEnum.FAIL.getCode());
        }

        // 转换为DO并保存
        RoleDO roleDO = rolePermissionConverter.command2RoleDO(command);
        roleMapper.insert(roleDO);

        // 返回新创建角色的ID
        return roleDO.getId();
    }

    /**
     * 更新角色(后台账号权限管理-角色管理)
     *
     * @param roleCommand 角色对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @OperateLog(dateType = "角色", operateType = 2)
    public void updateRole(RoleCommand roleCommand) {
        // 检查角色是否存在
        RoleDO existRole = roleMapper.selectById(roleCommand.getId());
        if (existRole == null) {
            throw new BusinessException("角色不存在", ResultCodeEnum.FAIL.getCode());
        }

        // 检查角色名称是否重复
        if (!existRole.getName().equals(roleCommand.getName())) {
            LambdaQueryWrapper<RoleDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(RoleDO::getName, roleCommand.getName());
            if (roleMapper.selectCount(queryWrapper) > 0) {
                throw new BusinessException("角色名称已存在", ResultCodeEnum.FAIL.getCode());
            }
        }

        // 转换为DO并更新
        RoleDO roleDO = rolePermissionConverter.command2RoleDO(roleCommand);
        roleMapper.updateById(roleDO);
    }

    /**
     * 更新角色权限关系(后台账号权限管理-角色管理)
     *
     * @param command 角色权限关系对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @OperateLog(dateType = "角色权限", operateType = 2)
    public void updateRolePermission(RolePermissionCommand command) {
        // 检查角色是否存在
        Long roleId = Long.valueOf(command.getRoleId());
        RoleDO roleDO = roleMapper.selectById(roleId);
        if (roleDO == null) {
            throw new BusinessException("角色不存在", 500);
        }

        // 先删除原有的角色权限关系
        LambdaQueryWrapper<RolePermissionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RolePermissionDO::getRoleId, roleId);
        remove(queryWrapper);

        // 如果有新的权限，则添加
        if (!CollectionUtils.isEmpty(command.getPermissions())) {
            List<RolePermissionDO> rolePermissionDOList = new ArrayList<>();
            for (String permissionId : command.getPermissions()) {
                RolePermissionDO rolePermissionDO = new RolePermissionDO();
                rolePermissionDO.setRoleId(roleId);
                rolePermissionDO.setPermissionId(Long.valueOf(permissionId));
                rolePermissionDOList.add(rolePermissionDO);
            }
            saveBatch(rolePermissionDOList);
        }
    }

    /**
     * 获取角色权限树(后台账号权限管理-角色管理点击授权时返回的角色授权树)
     *
     * @param roleId 角色ID
     * @return 返回角色权限树
     */
    @Override
    public RolePermissionDTO getRolePermissionList(Long roleId) {
        // 检查角色是否存在
        RoleDO roleDO = roleMapper.selectById(roleId);
        if (roleDO == null) {
            throw new BusinessException("角色不存在", 500);
        }

        // 获取系统所有权限
        List<PermissionDO> allPermissions = permissionMapper.selectList(null);
        List<PermissionDTO> permissionDTOList = rolePermissionConverter.employeePermissionDO2DTO(allPermissions);

        // 构建权限树
        List<PermissionDTO> permissionTree = buildPermissionTree(permissionDTOList);

        // 获取角色已分配的权限
        LambdaQueryWrapper<RolePermissionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RolePermissionDO::getRoleId, roleId);
        List<RolePermissionDO> rolePermissionDOList = list(queryWrapper);

        // 获取权限ID列表
        List<Long> permissionIds = rolePermissionDOList.stream().map(RolePermissionDO::getPermissionId).collect(Collectors.toList());

        // 如果没有权限，返回空列表
        if (permissionIds.isEmpty()) {
            List<String> emptyList = new ArrayList<>();
            RolePermissionDTO rolePermissionDTO = new RolePermissionDTO();
            rolePermissionDTO.setSystemPermissions(permissionTree);
            rolePermissionDTO.setAssignedPermissions(emptyList);
            return rolePermissionDTO;
        }

        // 查询权限码
        LambdaQueryWrapper<PermissionDO> permQueryWrapper = new LambdaQueryWrapper<>();
        permQueryWrapper.in(PermissionDO::getId, permissionIds);
        List<PermissionDO> permissions = permissionMapper.selectList(permQueryWrapper);

        // 提取权限码
        List<String> assignedPermissions = permissions.stream().map(PermissionDO::getPermissionCode).collect(Collectors.toList());

        // 构建返回结果
        RolePermissionDTO rolePermissionDTO = new RolePermissionDTO();
        rolePermissionDTO.setSystemPermissions(permissionTree);
        rolePermissionDTO.setAssignedPermissions(assignedPermissions);

        return rolePermissionDTO;
    }

    /**
     * 构建权限树
     *
     * @param permissionDTOList 权限DTO列表
     * @return 权限树
     */
    private List<PermissionDTO> buildPermissionTree(List<PermissionDTO> permissionDTOList) {
        // 根节点列表
        List<PermissionDTO> rootList = new ArrayList<>();
        // 所有节点的Map，以ID为键
        java.util.Map<String, PermissionDTO> permissionMap = new java.util.HashMap<>();

        // 将所有节点放入Map中
        for (PermissionDTO permissionDTO : permissionDTOList) {
            permissionMap.put(permissionDTO.getId(), permissionDTO);
        }

        // 遍历所有节点，构建树结构
        for (PermissionDTO permissionDTO : permissionDTOList) {
            String parentId = permissionDTO.getParentPermission();
            // 如果是根节点（父ID为空或不存在）
            if (!StringUtils.hasLength(parentId) || !permissionMap.containsKey(parentId)) {
                rootList.add(permissionDTO);
            } else {
                // 如果有父节点，则添加到父节点的children列表中
                PermissionDTO parentPermission = permissionMap.get(parentId);
                if (parentPermission.getChildren() == null) {
                    parentPermission.setChildren(new ArrayList<>());
                }
                parentPermission.getChildren().add(permissionDTO);
            }
        }

        return rootList;
    }

    /**
     * 删除角色(后台账号权限管理-角色管理)
     *
     * @param roleId 角色ID
     * @return 返回删除操作日志结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @OperateLog(dateType = "角色", operateType = 3)
    public DeleteRoleOperateDTO deleteRole(Long roleId) {
        // 检查角色是否存在
        RoleDO roleDO = roleMapper.selectById(roleId);
        if (roleDO == null) {
            throw new BusinessException("角色不存在", 500);
        }

        // 删除角色权限关系
        LambdaQueryWrapper<RolePermissionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RolePermissionDO::getRoleId, roleId);
        remove(queryWrapper);

        // 删除角色
        roleMapper.deleteById(roleId);

        // 构建操作日志
        return rolePermissionConverter.toDeleteRoleOperateDTO(roleDO);
    }

    /**
     * 删除角色权限(后台账号权限管理-角色管理)
     *
     * @param roleId       角色ID
     * @param permissionId 权限ID
     * @return 返回删除操作日志结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @OperateLog(dateType = "角色权限", operateType = 3)
    public DeleteRolePermissionOperateDTO deleteRolePermission(Long roleId, Long permissionId) {
        // 检查角色是否存在
        RoleDO roleDO = roleMapper.selectById(roleId);
        if (roleDO == null) {
            throw new BusinessException("角色不存在", ResultCodeEnum.FAIL.getCode());
        }

        // 检查权限是否存在
        PermissionDO permissionDO = permissionMapper.selectById(permissionId);
        if (permissionDO == null) {
            throw new BusinessException("权限不存在", ResultCodeEnum.FAIL.getCode());
        }

        // 删除角色权限关系
        LambdaQueryWrapper<RolePermissionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RolePermissionDO::getRoleId, roleId).eq(RolePermissionDO::getPermissionId, permissionId);
        remove(queryWrapper);

        // 构建操作日志
        return rolePermissionConverter.toDeleteRolePermissionOperateDTO(roleDO, permissionDO);
    }
}
